﻿<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>原生拼图小游戏代码</title>


    <style>
        .container {
            margin: 0 auto;
            width: 600px;
            height: 500px;
            /* background-color: red; */
        }

        input,
        button {
            outline: none;
            vertical-align: middle;
        }

        .copyInput {
            padding: 5px 5px;
            margin-right: 46px;
            border: 0;
            box-shadow: 0 0 2px purple;
        }

        .copyBtn {
            padding: 3px 10px;
            border: 0;
            box-shadow: 0 0 2px purple;
        }

        .pic-box {
            margin-top: 10px;
            width: 300px;
            height: 300px;
            /* background-color: red; */
            border: 1px solid #ccc;
        }

        .pic-box p {
            user-select: none;
            line-height: 300px;
            text-align: center;
        }

        .preview {
            width: 100%;
        }

        .saveBtn,
        .loadImage {

            padding: 3px 10px;

            margin: 5px 10px 5px 0;
        }


        /*  图片游戏2 */
        * {
            margin: 0;
            padding: 0;
            list-style: none;
            outline: none;
        }

        html,
        body {
            height: 100%;
            height: 100%;
        }

        .wrap {
            padding: 12px 0;
        }

        .btnBbox {
            margin: 0 auto;
            width: 600px;
            text-align: center;
        }

        .selectbox {
            display: inline-block;
            vertical-align: top;
        }

        .selectbox {
            display: inline-block;
            position: relative;
            width: 120px;

        }

        .selectbox .selectBtn {
            width: 100%;
            height: 40px;
            text-align: center;
            border: none;
            background: #ececec;
            border-radius: 5px;
            display: block;
            line-height: 40px;
            color: rgb(63, 63, 63);
            cursor: pointer;
            font-size: 16px;
            transition: all ease 0.2s;
        }



        .list-wrap {
            display: none;
            position: absolute;
            padding: 5px 0;
            width: 100%;
            height: 0;
            background: #ececec;
            color: rgb(102, 102, 102);
            border-radius: 5px;
            z-index: 10000;
            margin-top: 5px;

            font-size: 14px;
            transition: height .5s;
            overflow: hidden;

        }

        .list-wrap li {
            width: 100%;
            height: 30px;
            text-align: center;
            line-height: 30px;
            transition: all ease 0.2s;
            cursor: pointer;
        }

        .list-wrap li:hover {
            background: rgb(26, 187, 133);
            color: #fff;
        }

        .selectBtn.active {
            background: rgb(26, 187, 133);
            color: #fff;
        }

        .startBtn {
            width: 120px;
            border: none;
            background: rgb(51, 134, 230);
            color: #fff;
            border-radius: 5px;
            height: 40px;
            cursor: pointer;
            font-size: 16px;
            margin-right: 10px;
        }

        .startBtn:hover {
            background: rgb(56, 140, 236);
        }



        .pic {
            position: relative;
            margin: 30px auto;
            width: 600px;
            height: 600px;
        }

        .pic li {
            position: absolute;

            border-radius: 0;
            background-image: url('https://i.loli.net/2021/08/02/mGOiBdUp3WkRgoK.jpg');
            box-shadow: 0 0px 6px rgba(255, 255, 255, 0.6);
            cursor: pointer;

        }

        /*  图片游戏2 */



        /*  爱心 */
        .like {
            position: absolute;
        }

        /*  爱心 */


        /* vue */
        #app {
            margin-bottom: 100px;

            height: 500px;
            overflow: hidden;
        }

        #app button {
            padding: 3px 10px;
            margin: 5px;
        }

        #app .box {
            float: left;
            position: relative;
            width: 200px;
            height: 200px;
            text-align: center;
            background-color: var(--bg);
            line-height: 200px;
            font-size: 60px;
        }

        #game,
        #game div {
            box-sizing: border-box;
            /* position: absolute; */
            /* position: relative; */
        }

        /* vue */

        #routerContainer {
            padding: 10px 0;
        }

        .head {
            position: relative;
            padding-left: 20px;
            height: 50px;
            line-height: 50px;
            border-bottom: 1px solid #ccc;
            /* background-color: red; */
        }

        .head a {
            padding: 4px 10px;
            border-radius: 30px;
            color: #000;
            text-decoration: none;
        }

        .bottomBar {
            position: absolute;
            top: 10px;
            left: -100px;

            width: 100px;
            height: 30px;
            z-index: -5;
            border-radius: 30px;
            background-color: #d9bff3;
            transition: left .3s;
        }



        .head button {
            padding: 3px 10px;
            margin: 5px;
        }

        /* todolist */
        .todo-wrap {
            margin: 0 auto;
            width: 500px;
            min-height: 500px;
            border: 1px solid #ccc;
        }

        .todo-wrap input {
            height: 20px;
        }

        .todo-wrap button {
            padding: 3px 6px;
        }

        .todo-wrap .input-wrap {
            height: 50px;
            line-height: 50px;
        }

        .todo-wrap .input-wrap input {
            width: 200px;
        }

        .todo-wrap .input-wrap {

            text-align: center;
        }

        .todo-wrap .input-wrap .addBtn {
            margin-left: 10px;
        }

        .todo-wrap .item {

            width: 100%;
            height: 40px;
        }

        .todo-wrap ul {
            list-style: none;
        }


        .todo-wrap .item .edit-wrap {
            display: none;
            align-items: center;
            width: 100%;
            height: 100%;
        }

        .todo-wrap .item .content {
            display: flex;
            align-items: center;
            height: 100%;
        }

        .todo-wrap .item span {
            display: inline-block;
            max-width: 330px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            margin: 0 10px;
            font-size: 18px;
            /* background-color: red; */
        }

        .todo-wrap .item span.active {
            text-decoration: line-through;
            color: #999;
        }

        .todo-wrap .item button {
            margin-left: 8px;
        }

        .todo-wrap .item [type='checkbox'] {
            margin: 0 5px;
            width: 20px;
            height: 20px;
        }


        .todo-wrap .item .editBtn,
        .todo-wrap .item .saveBtn {
            background-color: yellow;
        }

        .todo-wrap .item .delBtn,
        .todo-wrap .item .escBtn {
            color: #fff;
            background-color: red;
        }

        .todo-wrap .editInput {
            margin-left: 30px;
            width: 200px;
        }
    </style>

</head>

<body>

    <header class="head" id="myHeader">
        <a href="#/home">项目介绍</a>
        <a href="#/game1">游戏1</a>
        <a href="#/game2">游戏2</a>
        <a href="#/mvvm">原生mvvm</a>
        <a href="#/download">图片预览下载</a>
        <a href="#/todolist">jsTodoList</a>
        <div class="bottomBar"></div>
    </header>

    <!-- 路由坑 -->
    <div id="routerContainer">
        <div style=" height: 50px;;text-align: center;">我是默认值</div>
    </div>


    <!-- 原生mvvm -->

    <script>

        // 图片游戏1
        ; (function (w, doc) {

            function component1() {
                let emptyDom = null;
                const config = {
                    width: 500,
                    height: 500,
                    row: 3,
                    col: 3,
                    imgUrl: 'https://i.loli.net/2021/08/02/DxKLUpgSed71Wty.png',
                    box: doc.querySelector('#game')
                }
                config.total = config.row * config.col;
                config.blockWidth = config.width / config.row;
                config.blockHeight = config.height / config.col;

                function createPointers() {
                    let arr = [];
                    for (let i = 0; i < config.row; i++) {
                        for (let j = 0; j < config.col; j++) {
                            arr.push({
                                x: config.blockWidth * i,
                                y: j * config.blockHeight
                            })
                        }
                    }
                    return arr
                }
                function getRandom(min, max) {
                    return Math.floor(Math.random() * (max - min + 1)) + min
                }
                function shuffle(arr) {
                    let item = null, idx = 0;
                    for (let i = 0; i < arr.length; i++) {
                        item = arr[i];
                        idx = getRandom(0, i)
                        arr[i] = arr[idx];
                        arr[idx] = item;
                    }
                    return arr
                }
                function createPic(pos, rightPos, appendToPage, oFarg) {
                    const { imgUrl, blockWidth, blockHeight } = config;
                    const oDiv = doc.createElement('div');
                    oDiv.style.position = 'absolute';
                    oDiv.style.left = pos.x + 'px';
                    oDiv.style.top = pos.y + 'px';
                    oDiv.style.width = blockWidth + 'px';
                    oDiv.style.height = blockHeight + 'px';
                    oDiv.style.border = '1px solid red';
                    oDiv.style.background = `url(${imgUrl})`
                    oDiv.style.backgroundPosition = `-${rightPos.x}px -${rightPos.y}px`
                    oDiv.style.transition = 'all .3s';
                    oDiv.currentX = rightPos.x
                    oDiv.currentY = rightPos.y
                    oDiv.onclick = function () {
                        let xdis = Math.abs(parseFloat(this.style.left) - parseFloat(emptyDom.style.left));
                        xdis = parseInt(xdis)


                        let ydis = Math.abs(parseFloat(this.style.top) - parseFloat(emptyDom.style.top));
                        ydis = parseInt(ydis)
                        console.log(xdis + ydis);

                        if ((xdis + ydis !== parseInt(blockWidth)) && (xdis + ydis !== parseInt(blockHeight))) {
                            console.log(6);
                            return
                        }
                        let x = this.style.left;
                        let y = this.style.top;
                        this.style.left = emptyDom.style.left
                        this.style.top = emptyDom.style.top
                        emptyDom.style.left = x
                        emptyDom.style.top = y;
                    }
                    if (appendToPage) {
                        oFarg.appendChild(oDiv)
                    } else {
                        emptyDom = oDiv
                    }
                }

                function creatGame() {
                    const { box, total, width, height } = config;
                    box.style.position = 'relative';
                    box.style.margin = '0px auto';
                    box.style.width = width + 'px'
                    box.style.height = height + 'px';
                    box.style.border = '1px solid #266';
                    box.onclick = function (e) {
                        e = e || w.event;
                        e.stopPropagation()
                    }
                    let oFarg = doc.createDocumentFragment();
                    let pointers = createPointers()
                    pointers = shuffle(pointers);
                    const rigthPointers = createPointers();
                    for (let i = 0; i < total; i++) {
                        if (i < total - 1) {
                            createPic(pointers[i], rigthPointers[i], true, oFarg)
                        } else {
                            createPic(pointers[i], rigthPointers[i], false, oFarg)
                        }
                    }
                    box.appendChild(oFarg)
                }


                creatGame()
            }

            w.component1 = component1
        })(window, document)


    </script>



    <script type="text/javascript">
            // 添加图片游戏
            ;
        (function (w, doc) {
            function initGame() {
                const btnBbox = doc.querySelector('.btnBbox')
                const startBtn = doc.querySelector('.startBtn')
                const selectBtn = doc.querySelector('.selectBtn');
                const pic = doc.querySelector('.pic');
                const ul = doc.querySelector('.list-wrap');
                const selectLi = ul.querySelectorAll('li');
                const offset = pic.getBoundingClientRect()
                const initLeft = offset.left,
                    initTop = offset.top,
                    picWidth = pic.offsetWidth,
                    picHeight = pic.offsetHeight;
                const eventType = ['onmousedown', 'onmouseup', 'onmouseover', 'onmouseout', 'onmousemove'];
                let timer = null,
                    starting = false,
                    randomArr = [],
                    originArr = [],
                    blockWidth,
                    blockHeight,
                    num = 3,
                    lastNum = 0,
                    firstIndex = 0,
                    img_list = null;
                renderView(num)
                initEvent();
                function renderView(n) {
                    pic.innerHTML = '';
                    originArr = [];
                    blockWidth = picWidth / n;
                    blockHeight = picHeight / n;

                    let index = -1,
                        li = null;
                    const oFrag = doc.createDocumentFragment();
                    for (let y = 0; y < n; y++) {
                        for (let x = 0; x < n; x++) {
                            li = doc.createElement('li');
                            li.setAttribute('data-index', ++index);

                            li.style.cssText = ` 
									left:${x * blockWidth}px ;
									top: ${y * blockHeight}px;
									width:${blockWidth}px;
									height:${blockHeight}px;
							background-position: ${-x * blockWidth}px  ${-y * blockHeight}px;
							opacity:1;
							z-index:0;  
					 transition :all 0.5s;  
									`
                            originArr.push(index);
                            oFrag.appendChild(li)
                        }
                    }
                    pic.appendChild(oFrag);
                    img_list = pic.querySelectorAll('li');

                }



                function initEvent() {
                    selectBtn.addEventListener('click', function (e) {
                        e = e || w.event;
                        e.preventDefault();
                        e.stopPropagation()
                        if (this.classList.contains('active')) {
                            ul.style.transition = 'all .5s';
                            ul.style.height = '0px';
                            setTimeout(() => {
                                ul.style.display = 'none'
                                this.classList.remove('active');
                            }, 450)
                        } else {
                            this.classList.add('active');
                            ul.style.display = 'block';
                            setTimeout(() => {
                                ul.style.transition = 'all .5s';
                                ul.style.height = '150px'
                            }, 20)
                        }
                    }, false);


                    ul.addEventListener('click', function (e) {
                        e = e || w.event;
                        e.preventDefault()
                        e.stopPropagation()
                        const target = e.target || e.srcElement;
                        if (target.tagName.toLowerCase() === 'li') {
                            const text = target.innerText;
                            const id = parseInt(target.dataset.id);
                            selectBtn.innerText = text;
                            selectBtn.click()
                            if (id === selectLi.length - 1) {
                                num = 12;
                                return
                            } else if (id === selectLi.length - 2) {
                                num = 8;
                                return
                            }
                            num = Math.floor(id * 1.5) + 3;
                        }
                    }, false);

                    startBtn.addEventListener('click', function (e) {
                        e = e || w.event;
                        e.preventDefault()
                        e.stopPropagation()
                        if (selectBtn.classList.contains('active')) {
                            selectBtn.click()
                        }

                        if (starting) {
                            starting = false
                            this.innerText = '开始';
                            cellOrder(originArr, num);
                            selectBtn.removeAttribute('disabled')
                            selectBtn.style.cursor = 'pointer';
                            img_list.forEach(dom => {
                                eventType.forEach(event => {
                                    dom[event] = null;
                                })
                            })
                        } else {

                            starting = true;
                            this.innerText = '复原';
                            selectBtn.setAttribute('disabled', true)
                            selectBtn.style.cursor = 'not-allowed'
                            if (lastNum !== num) {
                                renderView(num);
                                lastNum = num;
                                firstIndex = 0;
                            }
                            getRandomArr();
                            if (!firstIndex) {
                                firstIndex++;
                                cellOrder(randomArr, num, true);
                            } else {
                                cellOrder(randomArr, num);
                            }
                            drag()
                        }
                    }, false);

                    pic.addEventListener('click', e => {
                        e = e || w.event;
                        e.stopPropagation()
                    }, false)
                }


                function shuffle(min, max) {
                    return Math.floor(Math.random() * (max - min + 1)) + min
                }



                function getRandomArr() {
                    randomArr = originArr.slice();
                    let item, index;
                    for (let i = 0, len = randomArr.length; i < len; i++) {
                        item = randomArr[i];
                        index = shuffle(0, i);
                        randomArr[i] = randomArr[index];
                        randomArr[index] = item;
                    }
                }

                function cellOrder(arr, num, flag) {
                    let x, y, dom;
                    for (let i = 0, len = arr.length; i < len; i++) {
                        x = arr[i] % num;
                        y = Math.floor(arr[i] / num);
                        if (flag) {
                            dom = img_list[i];
                            animate1(dom, x * blockWidth, 'left');
                            animate1(dom, y * blockHeight, 'top');
                        } else {
                            animateFn(i, x, y)
                        }
                    }
                }



                function drag() {
                    var disX, disY, index1, index2;
                    img_list.forEach(v => {
                        v.onmousedown = function (e) {
                            e = e || w.event;
                            const offset = this.getBoundingClientRect();
                            disX = e.clientX - offset.left;
                            disY = e.clientY - offset.top;
                            this.style.transition = '0s';
                            this.style.zIndex = '99';
                            index1 = parseInt(this.dataset.index);
                            this.moving = true;
                        }
                        v.onmousemove = function (e) {
                            e = e || w.event;
                            e.preventDefault();
                            if (this.moving) {
                                this.style.left = e.clientX - disX - initLeft + 'px';
                                this.style.top = e.clientY - disY - initTop + 'px';
                            }
                        }
                        v.onmouseup = function (e) {
                            e = e || w.event;
                            if (!this.moving) {
                                return
                            }
                            this.moving = false;
                            const left = e.clientX - initLeft;
                            const top = e.clientY - initTop;
                            index2 = getIndex(left, top, index1, num);
                            if (index2 === index1) {
                                cellReturn(index1, num)
                            } else {
                                cellChange(index1, index2, num)
                            }
                        }
                        v.onmouseover = function () {
                            this.style.opacity = '.8'
                        }
                        v.onmouseout = function () {
                            this.style.opacity = '1';
                            this.moving = false;
                        }

                    })


                } //拖拽图片

                function getIndex(left, top, index, num) {
                    if (left < 0 || left > picWidth || top < 0 || top > picHeight) {
                        return index
                    }
                    const row = Math.floor(top / blockHeight);
                    const col = Math.floor(left / blockWidth);
                    const total = row * num + col;
                    for (let i = 0, len = randomArr.length; i < len; i++) {
                        if (randomArr[i] === total) {
                            return i
                        }
                    }
                }


                function cellReturn(index, num) {
                    const item = randomArr[index];
                    const x = item % num;
                    const y = Math.floor(item / num);
                    animateFn(index, x, y)
                }

                function cellChange(fromIndex, toIndex, num) {
                    const temp = randomArr[fromIndex]
                    const fromX = temp % num;
                    const fromY = Math.floor(temp / num);
                    const toX = randomArr[toIndex] % num;
                    const toY = Math.floor(randomArr[toIndex] / num);
                    animateFn(fromIndex, toX, toY);
                    animateFn(toIndex, fromX, fromY, function () {
                        randomArr[fromIndex] = randomArr[toIndex];
                        randomArr[toIndex] = temp;
                        timer && clearTimeout(timer)
                        timer = setTimeout(() => {
                            check()
                        }, 700);
                    })
                }


                function check() {
                    console.log('check');

                    if (originArr.toString() == randomArr.toString()) {

                        startBtn.click();
                        alert('你厉害算我输')
                    }
                }

                function animateFn(i, x, y, fn) {
                    const dom = img_list[i];
                    dom.style.left = x * blockWidth + 'px';
                    dom.style.top = y * blockHeight + 'px';
                    dom.style.zIndex = '0';
                    dom.style.transition = 'all .5s'
                    typeof fn === 'function' && fn();
                }

                function animate1(dom, target, name) {
                    const timerId = name + 'Id';



                    dom[timerId] && clearInterval(dom[timerId])
                    const offset = name === 'left' ? 'offsetLeft' : "offsetTop";
                    let speed = 500;

                    speed = target - dom[offset] > 0 ? speed : -speed;
                    dom[timerId] = setInterval(() => {

                        let dis = target - dom[offset];


                        dom.style[name] = dom[offset] + speed + 'px';
                        if (Math.abs(dis) <= Math.abs(speed)) {
                            dom.style[name] = target + 'px';
                            clearInterval(dom[timerId])
                        }
                    }, 30);
                }

            }




            w.initGame = initGame;
        })(window, document)
    </script>

    <script type="text/javascript">
            // 添加下载图片功能
            ;
        (function (window, document) {
            window.componentDownLoad = componentDownLoad

            function componentDownLoad(routerView) {
                routerView.innerHTML = `
 <div class="container">
        <input type="text" class="copyInput" placeholder="请输入要下载的图片地址"> <button class='copyBtn'>点击粘贴</button>
        <div class="pic-box">
            <p>请将文件拖到此处</p>
        </div>
        <input type="file" hidden id="inputFile" accept=".png,.jpg">
        <button class="loadImage">导入图片</button> <button class="saveBtn">下载</button>
        <ul>
            <li>
                https://pic.cnblogs.com/face/2462120/20210713155226.png
            </li>
            <li>
                https://pic1.zhimg.com/80/v2-fe0e61d4462a29805326f34c6342badc_720w.jpg
            </li>
            <li>
                https://i.loli.net/2021/08/02/DxKLUpgSed71Wty.png
            </li>
            <li>
                https://i.loli.net/2021/08/02/mGOiBdUp3WkRgoK.jpg
            </li>
        </ul>
    </div>`
                function checkImageUrlRight(imgSrc) {
                    return new Promise(function (resolve, reject) {
                        const img = new Image();
                        img.onload = function () {
                            resolve(true)
                        }
                        img.onerror = function () {
                            reject(false)
                        }
                        img.src = imgSrc;
                    })
                }

                document.querySelector('.container').addEventListener('click', function (e) {
                    e = e || window.event;

                    e.stopPropagation()
                }, false)

                const copyBtn = document.querySelector(".copyBtn");
                const copyInput = document.querySelector(".copyInput");
                const picBox = document.querySelector('.pic-box')
                const pEl = picBox.querySelector('p');
                const inputFile = document.getElementById('inputFile');
                const saveBtn = document.querySelector('.saveBtn');
                const loadImage = document.querySelector('.loadImage')
                let img = null;
                copyBtn.onclick = async function () {
                    copyInput.focus();
                    const text = await navigator.clipboard.readText();
                    copyInput.value = text;

                    try {
                        const flag = await checkImageUrlRight(text);
                        pEl.style.display = 'none';
                        if (!img) {
                            img = document.createElement('img');
                            img.className = 'preview'
                            picBox.appendChild(img)
                        }
                        img.src = text;
                        setTimeout(() => {

                            picBox.style.height = img.offsetHeight + 'px'
                        }, 20)
                    } catch (e) {
                        alert('请输入正确的图片地址')
                        pEl.style.display = 'block'
                    }

                }

                document.addEventListener('dragenter', event, false)
                document.addEventListener('dragover', event, false)
                document.addEventListener('dragleave', event, false)

                function event(e) {
                    e = e || window.event;
                    e.preventDefault();
                    e.stopPropagation()
                }
                loadImage.onclick = function (e) {

                    console.log(inputFile);

                    inputFile.click()
                }
                inputFile.onchange = function (e) {
                    const file = this.files[0];
                    const url = URL.createObjectURL(file);
                    if (!img) {
                        img = document.createElement('img');
                        img.className = 'preview'
                        picBox.appendChild(img);
                    }
                    img.src = url;
                    setTimeout(() => {
                        picBox.style.height = img.offsetHeight + 'px'
                    }, 20)
                    pEl.style.display = 'none'
                }
                picBox.addEventListener('drop', function (e) {
                    e = e || window.event;
                    e.preventDefault();
                    e.stopPropagation()
                    const files = e.dataTransfer.files[0];
                    if (files.type.indexOf('image') !== -1) {
                        try {
                            pEl.style.display = 'none';
                            const url = window.URL.createObjectURL(files)
                            if (!img) {
                                img = document.createElement('img');
                                img.src = url;
                                img.className = 'preview'
                                picBox.appendChild(img)
                            } else {
                                img.src = url;
                            }
                            setTimeout(() => {
                                picBox.style.height = img.offsetHeight + 'px'
                            }, 20)

                        } catch (e) {
                            pEl.style.display = 'block'
                        }
                        return
                    }
                    alert('请拖一个正确的图片')
                }, false)
                let index = 0;

                saveBtn.onclick = function () {
                    if (!img) {
                        return
                    }
                    index++;
                    downLoadImage(img.src, 'img' + index)
                }


                function downLoadImage(imgUrl, name) {
                    const img = new Image();
                    img.setAttribute('crossorigin', 'anonymous');
                    img.onload = function () {
                        const canvas = document.createElement('canvas');
                        canvas.width = img.width;
                        canvas.height = img.height;
                        const ctx = canvas.getContext('2d');
                        if (ctx) {
                            ctx.drawImage(img, 0, 0, img.width, img.height);
                            const url = canvas.toDataURL('image/png');
                            const a = document.createElement('a');
                            a.download = name || 'photo';
                            a.href = url;
                            a.click()
                        }
                    }
                    img.src = imgUrl
                }

            }
        })(window, document)
    </script>
    <script type="text/javascript">
            // 添加点击 ❤；
            ;
        (function (w, doc) {
            const oBody = doc.body;
            const likeArr = [];
            const titleArr = ['敬爱', '友善', '互助', '勤奋', '666', '你好'];
            const moveLike = () => {
                let item = null;
                for (let i = 0; i < likeArr.length; i++) {
                    item = likeArr[i];
                    if (item.opacity <= 0) {
                        oBody.removeChild(item.el);

                        likeArr.splice(i, 1);
                        return;
                    }
                    item.top -= 1.5;
                    item.opacity -= .01;
                    item.scale += .01;

                    item.el.style.cssText = `top:${item.top}px;
										left:${item.left}px; 
										color:${item.color};
										opacity:${item.opacity};
										transform:scale(${item.scale});
										`
                }
                requestAnimationFrame(moveLike)
            }
            const getColor = () => 256 * Math.random();
            const addLike = (e) => {
                const dom = doc.createElement('div');
                dom.className = 'like';
                dom.innerText = titleArr[Math.floor(Math.random() * titleArr.length)];
                oBody.appendChild(dom);
                likeArr.push({
                    el: dom,
                    color: `rgb(${getColor()}, ${getColor()},${getColor()})`,
                    opacity: 1,
                    scale: 1,
                    top: e.clientY - 10,
                    left: e.clientX - 10
                })
                moveLike()
            }
            oBody.addEventListener('click', e => {
                e = e || w.event;
                addLike(e);
            }, false)
        })(window, document)
    </script>

    <script>
        console.log('class vue --start');

        //  vue  数据劫持
        ((w, doc) => {
            class Dep {
                constructor() {
                    this.adds = [];
                }
                addSub(watcher) {
                    this.adds.push(watcher);
                }
                notify() {
                    this.adds.forEach((watcher) => watcher.update());
                }
            }
            class Watcher {
                constructor(vm, key, cb) {
                    this.vm = vm;
                    (this.key = key), (this.cb = cb);
                    Dep.target = this;
                    key.split(".").reduce((obj, k) => obj[k], vm);
                    Dep.target = null;
                }
                update() {
                    const value = this.key.split(".").reduce((obj, k) => obj[k], this.vm);
                    this.cb(value);
                }
            }
            const subscriber = new Dep();
            class Computed {
                constructor() {
                    this.computedData = []
                }
                addComputed(vm, computed, key) {
                    const desc = Object.getOwnPropertyDescriptor(computed, key);
                    const descFn = desc.value.get ? desc.value.get : desc.value;
                    const value = descFn.call(vm);
                    const dep = this.collectDep(descFn);
                    const get = descFn.bind(vm)
                    this.addComputedProps({
                        key,
                        value,
                        dep,
                        get
                    })
                    const dataItem = this.computedData.find(v => v.key === key);
                    Object.defineProperty(vm, key, {
                        get() {
                            Dep.target && subscriber.addSub(Dep.target);
                            return dataItem.value
                        }

                    });
                }
                addComputedProps(props) {
                    this.computedData.push(props)
                }
                collectDep(fn) {
                    const matched = fn.toString().match(/this\.{1}(\S+)/g);
                    return matched.map(v => v.split('.')[1])
                }
                update(key) {
                    this.computedData.forEach(v => {
                        const dep = v.dep;
                        const _key = dep.find(k => k === key);
                        if (_key) {
                            v.value = v.get();
                            subscriber.notify();
                        }
                    })
                }
            }

            class Watch {
                constructor() {
                    this.watchData = []
                }
                addWatch(vm, watch, key) {
                    this.addWatchProps({
                        key,
                        fn: watch[key].bind(vm)
                    })
                }
                addWatchProps(props) {
                    this.watchData.push(props)
                }
                invoke(key, newVal, oldVal) {
                    this.watchData.forEach(v => {
                        if (v.key === key) {
                            v.fn(newVal, oldVal)
                        }
                    })
                }
            }
            class Vue {
                constructor(options) {
                    const {
                        el,
                        data,
                        methods,
                        watch,
                        computed
                    } = options

                    this.$data = typeof data === 'function' ? data.call(this) : data;
                    this.$el = doc.querySelector(el);
                    this.methods = methods;
                    this.eventPool = new Map();
                    this.showPool = new Map();
                    this.init(watch, computed)
                }
                init(watch, computed) {
                    // 数据劫持
                    this.defineReactiveData(this.$data)
                    // 代理到 this 身上
                    this.initProxy(this, (key, value) => {

                    }, (key, newVal, oldVal) => {
                        if (newVal === oldVal) {
                            return
                        }
                        this.$computed(key);
                        this.$watch(key, newVal, oldVal)
                    })
                    const computedIns = this.initComputed(this, computed);
                    const watchIns = this.initWatch(this, watch);
                    this.$computed = computedIns.update.bind(computedIns);
                    this.$watch = watchIns.invoke.bind(watchIns)

                    this.compile(this)
                    this.initEvent(this.eventPool);

                }
                initComputed(vm, computed) {
                    const computedIns = new Computed();
                    for (let k in computed) {
                        computedIns.addComputed(vm, computed, k)
                    }
                    return computedIns
                }
                initWatch(vm, watch) {
                    const watchIns = new Watch();
                    for (let k in watch) {
                        watchIns.addWatch(vm, watch, k);
                    }
                    return watchIns
                }


                compile(vm) {
                    let oFrag = doc.createDocumentFragment(),
                        firstChild = null;
                    while ((firstChild = vm.$el.firstChild)) {
                        oFrag.appendChild(firstChild);
                    }
                    this.initView(oFrag, vm);
                    vm.$el.appendChild(oFrag);
                }
                initEvent(eventPool) {
                    for (let [k, v] of eventPool) {
                        k.addEventListener('click', v.fn.bind(this), false)
                    }
                    this.changeEvent(null, this.showPool)
                }
                initProxy(vm, _get, _set) {
                    const data = this.$data
                    Object.keys(data).forEach(k => {
                        const oldVal = vm.$data[k]
                        Object.defineProperty(vm, k, {
                            enumerable: true,
                            configurable: true,
                            get() {
                                _get(k, oldVal)
                                Dep.target && subscriber.addSub(Dep.target);
                                return vm.$data[k]
                            },
                            set(val) {
                                vm.changeEvent(k, vm.showPool)
                                vm.$data[k] = val;
                                _set(k, val, oldVal)
                                subscriber.notify();
                            }
                        })
                    })
                }
                defineReactiveData(data) {
                    if (typeof data !== 'object' || !data) {
                        return
                    }
                    Object.keys(data).forEach(k => {
                        let value = data[k];
                        this.defineReactiveData(data[k]);
                        Object.defineProperty(data, k, {
                            enumerable: true,
                            configurable: true,
                            get() {
                                return value;
                            },
                            set(val) {
                                value = val;
                                subscriber.notify();
                            },
                        });

                    })
                }
                initView(node, vm) {
                    const reg = /\{\{\s*(\S+)\s*\}\}/g;
                    const childNodes = node.childNodes;
                    if (!childNodes.length) {
                        return;
                    }
                    childNodes.forEach(dom => {
                        if (dom.nodeType === 1 && dom.tagName === "INPUT") {
                            const attrs = Array.from(dom.attributes);
                            const result = attrs.find((v) => v.name === "v-model");
                            if (result) {
                                const key = result.value;
                                const keyArr = key.split(".");
                                const value = keyArr.reduce((obj, k) => obj[k], vm);
                                dom.value = value;
                                new Watcher(vm, key, (newVal) => {
                                    dom.value = newVal;
                                });
                                dom.addEventListener(
                                    "input",
                                    (e) => {
                                        const el = e || w.event;
                                        const lastK = keyArr[keyArr.length - 1];
                                        const obj = keyArr
                                            .slice(0, keyArr.length - 1)
                                            .reduce((obj, k) => obj[k], vm);
                                        console.log(obj[lastK]);
                                        obj[lastK] = el.target.value;
                                    },
                                    false
                                );
                            }

                        } else if (dom.nodeType === 1) {
                            const vshow = dom.getAttribute('v-show');
                            const vif = dom.getAttribute('v-if');
                            const evet = dom.getAttribute('@click');
                            if (vif) {
                                this.showPool.set(dom, {
                                    type: 'vif',
                                    show: this.$data[vif],
                                    key: vif
                                })
                            } else if (vshow) {
                                this.showPool.set(dom, {
                                    type: 'vshow',
                                    show: this.$data[vshow],
                                    key: vshow
                                })
                            }
                            if (evet) {
                                this.eventPool.set(dom, {
                                    type: 'click',
                                    fn: this.methods[evet],
                                    event: evet
                                })
                            }

                        } else if (dom.nodeType === 3) {
                            const text = dom.textContent;
                            const execRes = reg.exec(text);
                            if (execRes) {
                                const key = execRes[1];

                                const value = key.split(".").reduce((obj, k) => obj[k], vm);

                                dom.textContent = text.replace(reg, value);
                                new Watcher(vm, key, (newVal) => {
                                    console.log(newVal);
                                    dom.textContent = text.replace(reg, newVal);
                                });
                            }
                            return;
                        }
                        this.initView(dom, vm)
                    })
                }
                changeEvent(data, showPool) {
                    if (!data) {
                        for (let [k, v] of showPool) {
                            switch (v.type) {
                                case 'vshow':
                                    !v.show && (k.style.display = 'none');
                                    break;
                                case 'vif':
                                    v.comment = doc.createComment('v-if');
                                    !v.show && k.parentNode.replaceChild(v
                                        .comment, k);
                                    break;
                            }
                        }
                        return
                    }
                    for (let [k, v] of showPool) {
                        if (data === v.key) {
                            switch (v.type) {
                                case 'vshow':
                                    v.show ? (k.style.display = 'none') : (k.style.display = 'block')
                                    v.show = !v.show;
                                    break;
                                case 'vif':
                                    v.show ? k.parentNode.replaceChild(v.comment, k) : v.comment.parentNode
                                        .replaceChild(k, v.comment)
                                    v.show = !v.show;
                                    break;
                            }
                        }
                    }

                }
            }




            console.log('class vue --end');
            w.Vue = Vue;
        })(window, document);
    </script>
    <script>
        console.log('componentMvvm---start');
        function componentMvvm(routeView) {
            routeView.innerHTML = `<div id="app">
        <h3>姓名是：{{name}}</h3>
        <h3>年龄是：{{ age }} <span>title的值是：{{title}}</span> </h3>
        <h3>info.a的值是：{{info.a}}</h3>
        <div>name的值：<input type="text" v-model="name" /></div>
        <div>info.a的值：<input type="text" v-model="info.a" /></div>
        <br>
     
        <h3><button @click="add1">点击num1</button>   <span>num1的值是：{{num1}}</span> </h3>
        <h3><button @click="add2">点击num2</button> <span>num2的值是：{{num2}}</span> </h3>
        <h3> computed total 的值为：{{total}} </h3>
        <br>
        <button @click="box1">点击1</button>
        <button @click="box2">点击2</button>
        <button @click="box3">点击3</button>
        <button @click="box4">点击4</button>
        <br>
        <div class="box" v-show='showbox1' style="--bg:red">1</div>
        <div class="box" v-if='ifbox2' style="--bg:purple">2</div>
        <div class="box" v-if='ifbox3' style="--bg:yellow">3</div>
        <div class="box" v-show='showbox4' style="--bg:brown">4</div>

    </div>`;

            let vm = new Vue({
                el: '#app',
                data() {
                    return {
                        name: 'zs',
                        age: 20,
                        showbox1: false,
                        ifbox2: false,
                        ifbox3: false,
                        showbox4: false,
                        info: {
                            a: 'a1',
                            c: 'c1'
                        },
                        title: '学生列表',
                        classNum: 1,
                        num1: 1,
                        num2: 2
                    }
                },
                methods: {
                    add1() {
                        this.num1++
                    },
                    add2() {
                        this.num2 += 2
                    },
                    box1() {
                        this.showbox1 = !this.showbox1;
                    },
                    box2() {
                        this.ifbox2 = !this.ifbox2;
                    },
                    box3() {
                        this.ifbox3 = !this.ifbox3;
                    },
                    box4() {
                        this.showbox4 = !this.showbox4;
                    },
                },
                computed: {
                    total() {
                        console.log('total');
                        return this.num1 + this.num2

                    }
                },
                watch: {
                    num1(newVal, oldVal) {
                        console.log('key', 'newVal', 'oldVal');
                        console.log('num1', newVal, oldVal);
                    },
                    num2(newVal, oldVal) {
                        console.log('key', 'newVal', 'oldVal');
                        console.log('num2', newVal, oldVal);
                    }
                }
            });
            console.log(vm)
        }
    </script>



    <script>
        ; (function (w, doc) {

            function componentTodoList(routerView) {

                routerView.innerHTML = `<div class="todo-wrap">
        <div class="input-wrap">
            <input type="text" class="addInput"> <button class="addBtn">add</button>
        </div>
        <ul class="list">
        </ul>
            </div>`;
                const addInput = doc.querySelector('.addInput'),
                    addBtn = doc.querySelector('.addBtn'),
                    ul = doc.querySelector('.list');
                const storage = function (name, defaultValue) {
                    const getItem = function () {
                        return JSON.parse(localStorage.getItem(name) || defaultValue)
                    }
                    const setItem = function (value) {
                        localStorage.setItem(name, JSON.stringify(value))
                    }
                    return {
                        getItem,
                        setItem
                    }
                }
                const todoStorage = storage('todo_list', '[]');
                let todoList = todoStorage.getItem();
                function renderView(list) {
                    if (!list.length) {
                        return
                    }
                    // ul.innerHTML = '';
                    let htmlStr = '',
                        completedNum = 0;
                    list.forEach(v => {
                        if (v.completed) {
                            completedNum++
                        }
                        htmlStr += `<li class="item" >
                <div class="content" data-id='${v.id}' >
                    <input type="checkbox" ${v.completed ? 'checked' : ''}> 
                    <span ${v.completed ? 'class="active"' : ''} >${v.content}</span>
                    <button class='editBtn'>修改</button>
                    <button class='delBtn'>删除</button>
                </div>
                <div class="edit-wrap" data-id='${v.id}' >
                    <input type="text" class="editInput" > <button class='saveBtn'>确定</button>             
                </div>
            </li>`
                    })
                    ul.innerHTML = htmlStr;
                }
                addInput.focus()
                renderView(todoList);
                addBtn.onclick = function () {
                    const value = addInput.value.trim();
                    if (!value) {
                        return
                    }
                    const obj = {
                        content: value,
                        completed: false,
                        id: Date.now() + ''
                    }
                    todoList.push(obj);
                    renderView(todoList);
                    addInput.value = '';
                    todoStorage.setItem(todoList);
                }
                addInput.addEventListener('keyup', e => {
                    e = e || w.event;
                    if (e.keyCode === 13) {
                        addBtn.click()
                    }
                }, false)

                let editFlag = false,
                    beforeValue = '',
                    nowValue = '',
                    id = 0,
                    inputEl = null;
                ul.addEventListener('click', e => {
                    e = e || w.event;
                    const target = e.target || e.srcElement;
                    let parent = target.parentNode;
                    id = parent.dataset.id;
                    if (target.tagName.toLowerCase() === 'input') {


                        if (!editFlag) {
                            // 点击的是checkbox
                            const spanEl = parent.querySelector('span')
                            const checked = target.checked

                            if (checked) {
                                spanEl.className = 'active';
                            } else {
                                spanEl.className = ''
                            }
                            todoList = todoList.map(v => {
                                if (v.id === id) {
                                    v.completed = checked
                                }
                                return v
                            })
                            todoStorage.setItem(todoList)
                            return
                        }
                    }

                    if (target.tagName.toLowerCase() === 'button') {

                        if (!editFlag) {
                            //  edit
                            if (target.classList.contains('editBtn')) {
                                editFlag = true;
                                parent.style.display = 'none';
                                const editWrap = parent.parentNode.querySelector('.edit-wrap');
                                inputEl = editWrap.querySelector('input');

                                const saveBtn = editWrap.querySelector('.saveBtn')
                                editWrap.style.display = 'flex';
                                todoList.forEach(v => {
                                    if (v.id === id) {
                                        beforeValue = v.content;
                                        nowValue = v.content;
                                        return
                                    }
                                })
                                inputEl.value = nowValue;
                                inputEl.focus();
                                inputEl.onkeyup = function (e) {
                                    e = e || w.event;
                                    if (e.keyCode === 13) {
                                        saveBtn.click();
                                    }
                                }

                                inputEl.onblur = function () {
                                    saveBtn.click();
                                }
                                return
                            }


                            //  del
                            parent = parent.parentNode;
                            ul.removeChild(parent)
                            todoList = todoList.filter(v => v.id !== id)
                            todoStorage.setItem(todoList)
                            return
                        }


                        editFlag = false;
                        const value = inputEl.value.trim()

                        console.log(target);

                        // escBtn
                        if (target.classList.contains('escBtn')) {
                            // console.log('quxu');

                            // //  重新渲染
                            // renderView(todoList)
                            // return

                        } else {
                            // saveBtn  
                            if (!value || value === beforeValue) {
                                // 没有值 重新渲染
                                renderView(todoList)
                                return
                            }
                        }

                        // 有值；修改重新渲染
                        const item = todoList.find(v => v.id == id)
                        item.content = value;
                        renderView(todoList)
                        todoStorage.setItem(todoList)
                    }
                }, false)
            }

            w.componentTodoList = componentTodoList
        })(window, document)
    </script>
    <script>
            ; (function (w, doc) {
                class Router {
                    constructor() {
                        this.curUrl = '';
                        this.routerOrder = {};
                        this.init()
                    }
                    init() {
                        w.addEventListener('hashchange', this.reloadPage.bind(this), false)
                    }
                    reloadPage() {
                        this.curUrl = location.hash.substring(1);
                        if (!this.curUrl) {
                            this.curUrl = 'default'
                        }
                        this.routerOrder[this.curUrl]()
                    }
                    map(key, cb) {
                        this.routerOrder[key] = cb
                    }
                }

                const myRouter = new Router();
                const head = doc.querySelector('.head')
                const bottomBar = head.querySelector('.bottomBar');

                head.addEventListener('click', (e) => {
                    e = e || window.event;
                    const target = e.target
                    if (target.tagName === 'A') {
                        bottomBar.style.width = target.offsetWidth + 'px';
                        bottomBar.style.left = target.offsetLeft + 'px'
                    }
                }, false)


                const routeView = doc.getElementById('routerContainer');
                function showHome() {
                    return `   <ul style="width: 800px;margin: 50px auto; ">
            <li style=" list-style:disc; ">项目加入原生实现路由切换功能</li>
            <li style=" list-style:disc; ">原生实现拼图游戏1，2</li>
            <li style=" list-style:disc; ">原生实现将系统剪切板url复制到input框，拖拽，点击进行预览图片，下载图片</li>
            <li style=" list-style:disc; ">原生实现mvvm，v-if v-show  computed  watch  </li>
            <li style=" list-style:disc; ">原生实现点击页面出现随机字上浮动，类似点击关注❤ 上浮动</li>
            <li style=" list-style:disc; ">原生todoList永久本地存储，修改后失去焦点判断</li>
            <li style=" list-style:disc; ">增加tabBar筋抖云</li>
        </ul>`
                }


                function showGame2(routerView) {
                    routerView.innerHTML = `<div class="wrap">
        <div class="btnBbox">
            <button class="startBtn" type="button">开始</button>
            <div class="selectbox">
                <button class="selectBtn">简单</button>
                <ul class="list-wrap">
                    <li data-id="0">简单</li>
                    <li data-id="1">入门</li>
                    <li data-id="2">中等难度</li>
                    <li data-id="3">高难</li>
                    <li data-id="4">外星人</li>
                </ul>
            </div>
        </div>
        <ul class="pic"></ul>
    </div>`;

                }

                myRouter.map('/home', () => {
                    routeView.innerHTML = showHome()
                })
                myRouter.map('/game1', () => {
                    routeView.innerHTML = `<div id="game"> </div>`
                    component1()
                })
                myRouter.map('/game2', () => {
                    showGame2(routeView);
                    initGame()
                })
                myRouter.map('/mvvm', () => {
                    componentMvvm(routeView);
                })
                myRouter.map('/download', () => {
                    componentDownLoad(routeView);
                })
                myRouter.map('/todolist', () => {
                    componentTodoList(routeView);
                })

                myRouter.map('default', () => {
                    routeView.innerHTML = `<div style=" height: 50px;;text-align: center;">我是默认值</div>`;
                })
                console.log(myRouter);

                myRouter.reloadPage()

            })(window, document)
    </script>

</body>

</html>

</html>